home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Oracle Corporation code.
- *
- * The Initial Developer of the Original Code is
- * Oracle Corporation
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
- //
- // calCompositeCalendar.js
- //
-
- const calIOperationListener = Components.interfaces.calIOperationListener;
-
- function calCompositeCalendarObserverHelper (compCalendar) {
- this.compCalendar = compCalendar;
- this.pendingLoads = {};
- }
-
- calCompositeCalendarObserverHelper.prototype = {
- pendingLoads: null,
-
- onStartBatch: function() {
- this.compCalendar.mObservers.notify("onStartBatch");
- },
-
- onEndBatch: function() {
- this.compCalendar.mObservers.notify("onEndBatch");
- },
-
- onLoad: function(calendar) {
- // avoid unnecessary onLoad events:
- if (this.pendingLoads[calendar.id]) {
- // don't forward if caused by composite:
- delete this.pendingLoads[calendar.id];
- } else {
- // any refreshed dependent calendar logically refreshes
- // this composite calendar, thus we send out an onLoad
- // for this composite calendar:
- this.compCalendar.mObservers.notify("onLoad", [this.compCalendar]);
- }
- },
-
- onAddItem: function(aItem) {
- this.compCalendar.mObservers.notify("onAddItem", arguments);
- },
-
- onModifyItem: function(aNewItem, aOldItem) {
- this.compCalendar.mObservers.notify("onModifyItem", arguments);
- },
-
- onDeleteItem: function(aDeletedItem) {
- this.compCalendar.mObservers.notify("onDeleteItem", arguments);
- },
-
- onError: function(aErrNo, aMessage) {
- this.compCalendar.mObservers.notify("onError", arguments);
- },
-
- onPropertyChanged: function(aCalendar, aName, aValue, aOldValue) {
- this.compCalendar.mObservers.notify("onPropertyChanged", arguments);
- },
-
- onPropertyDeleting: function(aCalendar, aName) {
- this.compCalendar.mObservers.notify("onPropertyDeleting", arguments);
- }
- };
-
- function calCompositeCalendar () {
- this.mObserverHelper = new calCompositeCalendarObserverHelper(this);
- this.wrappedJSObject = this;
-
- this.mCalendars = new Array();
- this.mCompositeObservers = new calListenerBag(Components.interfaces.calICompositeObserver);
- this.mObservers = new calListenerBag(Components.interfaces.calIObserver);
- this.mDefaultCalendar = null;
- }
-
- calCompositeCalendar.prototype = {
- //
- // private members
- //
- mDefaultCalendar: null,
-
- //
- // nsISupports interface
- //
- QueryInterface: function (aIID) {
- if (!aIID.equals(Components.interfaces.nsISupports) &&
- !aIID.equals(Components.interfaces.calICalendarProvider) &&
- !aIID.equals(Components.interfaces.calICalendar) &&
- !aIID.equals(Components.interfaces.calICompositeCalendar))
- {
- throw Components.results.NS_ERROR_NO_INTERFACE;
- }
-
- return this;
- },
-
- //
- // calICalendarProvider interface
- //
- get prefChromeOverlay() {
- return null;
- },
-
- get displayName() {
- return calGetString("calendar", "compositeName");
- },
-
- createCalendar: function comp_createCal() {
- throw NS_ERROR_NOT_IMPLEMENTED;
- },
-
- deleteCalendar: function comp_deleteCal(cal, listener) {
- // You shouldn't be able to delete from the composite calendar.
- throw NS_ERROR_NOT_IMPLEMENTED;
- },
-
- //
- // calICompositeCalendar interface
- //
-
- mCalendars: null,
- mDefaultCalendar: null,
- mPrefPrefix: null,
- mDefaultPref: null,
- mActivePref: null,
-
- set prefPrefix (aPrefPrefix) {
- if (this.mPrefPrefix) {
- this.mCalendars.forEach(this.removeCalendar, this);
- }
- this.mPrefPrefix = aPrefPrefix;
- this.mActivePref = aPrefPrefix + "-in-composite";
- this.mDefaultPref = aPrefPrefix + "-default";
- var mgr = getCalendarManager();
- var cals = mgr.getCalendars({});
-
- cals.forEach(function (c) {
- if (c.getProperty(this.mActivePref))
- this.addCalendar(c);
- if (c.getProperty(this.mDefaultPref))
- this.setDefaultCalendar(c, false);
- }, this);
- },
-
- get prefPrefix () {
- return this.mPrefPrefix;
- },
-
- addCalendar: function (aCalendar) {
- // check if the calendar already exists
- for each (cal in this.mCalendars) {
- if (aCalendar.uri.equals(cal.uri)) {
- // throw exception if calendar already exists?
- return;
- }
- }
-
- // add our observer helper
- aCalendar.addObserver(this.mObserverHelper); // XXX Never removed!
-
- this.mCalendars.push(aCalendar);
- if (this.mPrefPrefix) {
- aCalendar.setProperty(this.mActivePref, true);
- }
- this.mCompositeObservers.notify("onCalendarAdded", [aCalendar]);
-
- // if we have no default calendar, we need one here
- if (this.mDefaultCalendar == null)
- this.setDefaultCalendar(aCalendar, false);
- },
-
- removeCalendar: function (aServer) {
- var newCalendars = Array();
- var calToRemove = null;
- for each (cal in this.mCalendars) {
- if (!aServer.equals(cal.uri))
- newCalendars.push(cal);
- else
- calToRemove = cal;
- }
-
- if (calToRemove) {
- this.mCalendars = newCalendars;
- if (this.mPrefPrefix) {
- calToRemove.deleteProperty(this.mActivePref);
- calToRemove.deleteProperty(this.mDefaultPref);
- }
- calToRemove.removeObserver(this.mObserverHelper);
- this.mCompositeObservers.notify("onCalendarRemoved", [calToRemove]);
- }
- },
-
- getCalendar: function (aServer) {
- for each (cal in this.mCalendars) {
- if (aServer.equals(cal.uri))
- return cal;
- }
-
- return null;
- },
-
- get calendars() {
- // return a nsISimpleEnumerator of this array. This sucks.
- // XXX make this an array, like the calendar manager?
- return null;
- },
-
- get defaultCalendar() {
- return this.mDefaultCalendar;
- },
-
- setDefaultCalendar: function (cal, usePref) {
- // don't do anything if the passed calendar is the default calendar!
- if (this.mDefaultCalendar && cal && this.mDefaultCalendar.uri.equals(cal.uri))
- return;
- if (usePref && this.mPrefPrefix) {
- if (this.mDefaultCalendar) {
- this.mDefaultCalendar.deleteProperty(this.mDefaultPref);
- }
- // if not null set the new calendar as default in the preferences
- if (cal) {
- cal.setProperty(this.mDefaultPref, true);
- }
- }
- this.mDefaultCalendar = cal;
- this.mCompositeObservers.notify("onDefaultCalendarChanged", [cal]);
- },
-
- set defaultCalendar(v) {
- this.setDefaultCalendar(v, true);
- },
-
- //
- // calICalendar interface
- //
- // Write operations here are forwarded to either the item's
- // parent calendar, or to the default calendar if one is set.
- // Get operations are sent to each calendar.
- //
-
- get id() {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
- set id(id) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- get superCalendar() {
- // There shouldn't be a superCalendar for the composite
- return this;
- },
- set superCalendar(val) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- // this could, at some point, return some kind of URI identifying
- // all the child calendars, thus letting us create nifty calendar
- // trees.
- get uri() {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
- set uri(v) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- get readOnly() {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
- set readOnly(bool) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- get canRefresh() {
- return true;
- },
-
- get name() {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
- set name(v) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- get type() {
- return "composite";
- },
-
- getProperty: function(aName) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
- setProperty: function(aName, aValue) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
- deleteProperty: function(aName) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- // void addObserver( in calIObserver observer );
- mCompositeObservers: null,
- mObservers: null,
- addObserver: function (aObserver) {
- if (aObserver instanceof Components.interfaces.calICompositeObserver) {
- this.mCompositeObservers.add(aObserver);
- }
- this.mObservers.add(aObserver);
- },
-
- // void removeObserver( in calIObserver observer );
- removeObserver: function (aObserver) {
- if (aObserver instanceof Components.interfaces.calICompositeObserver) {
- this.mCompositeObservers.remove(aObserver);
- }
- this.mObservers.remove(aObserver);
- },
-
- refresh: function() {
- for each (cal in this.mCalendars) {
- try {
- if (cal.canRefresh) {
- this.mObserverHelper.pendingLoads[cal.id] = true;
- cal.refresh();
- }
- } catch (e) {
- ASSERT(false, e);
- delete this.mObserverHelper.pendingLoads[cal.id];
- }
- }
- // send out a single onLoad for this composite calendar,
- // although e.g. the ics provider will trigger another
- // onLoad asynchronously; we cannot rely on every calendar
- // sending an onLoad:
- this.mObservers.notify("onLoad", [this]);
- },
-
- // void modifyItem( in calIItemBase aNewItem, in calIItemBase aOldItem, in calIOperationListener aListener );
- modifyItem: function (aNewItem, aOldItem, aListener) {
- if (aNewItem.calendar == null) {
- // XXX Can't modify item with NULL parent
- throw Components.results.NS_ERROR_FAILURE;
- }
-
- return aNewItem.calendar.modifyItem(aNewItem, aOldItem, aListener);
- },
-
- // void deleteItem( in string id, in calIOperationListener aListener );
- deleteItem: function (aItem, aListener) {
- if (aItem.calendar == null) {
- // XXX Can't delete item with NULL parent
- throw Components.results.NS_ERROR_FAILURE;
- }
-
- return aItem.calendar.deleteItem(aItem, aListener);
- },
-
- // void addItem( in calIItemBase aItem, in calIOperationListener aListener );
- addItem: function (aItem, aListener) {
- return this.mDefaultCalendar.addItem(aItem, aListener);
- },
-
- // void getItem( in string aId, in calIOperationListener aListener );
- getItem: function (aId, aListener) {
- var cmpListener = new calCompositeGetListenerHelper(this.mCalendars.length, aListener);
- for each (cal in this.mCalendars) {
- try {
- cmpListener.opGroup.add(cal.getItem(aId, cmpListener));
- } catch (exc) {
- ASSERT(false, exc);
- }
- }
- return cmpListener.opGroup;
- },
-
- // void getItems( in unsigned long aItemFilter, in unsigned long aCount,
- // in calIDateTime aRangeStart, in calIDateTime aRangeEnd,
- // in calIOperationListener aListener );
- getItems: function (aItemFilter, aCount, aRangeStart, aRangeEnd, aListener) {
- // If there are no calendars, then we just call onOperationComplete
- if (this.mCalendars.length == 0) {
- aListener.onOperationComplete (this,
- Components.results.NS_OK,
- calIOperationListener.GET,
- null,
- null);
- return;
- }
-
- var cmpListener = new calCompositeGetListenerHelper(this.mCalendars.length, aListener, aCount);
- for (cal in this.mCalendars) {
- try {
- cmpListener.opGroup.add(
- this.mCalendars[cal].getItems(
- aItemFilter, aCount, aRangeStart, aRangeEnd, cmpListener));
- } catch (exc) {
- ASSERT(false, exc);
- }
- }
- return cmpListener.opGroup;
- },
-
- startBatch: function ()
- {
- this.mCompositeObservers.notify("onStartBatch");
- },
- endBatch: function ()
- {
- this.mCompositeObservers.notify("onEndBatch");
- }
- };
-
- // composite listener helper
- function calCompositeGetListenerHelper(aNumQueries, aRealListener, aMaxItems) {
- this.wrappedJSObject = this;
- this.mNumQueries = aNumQueries;
- this.mRealListener = aRealListener;
- this.mMaxItems = aMaxItems;
- }
-
- calCompositeGetListenerHelper.prototype = {
- mNumQueries: 0,
- mRealListener: null,
- mOpGroup: null,
- mReceivedCompletes: 0,
- mFinished: false,
- mMaxItems: 0,
- mItemsReceived: 0,
-
- get opGroup() {
- if (!this.mOpGroup) {
- var this_ = this;
- function cancelFunc() { // operation group has been cancelled
- var listener = this_.mRealListener;
- this_.mRealListener = null;
- if (listener) {
- listener.onOperationComplete(
- this_, Components.interfaces.calIErrors.OPERATION_CANCELLED,
- calIOperationListener.GET, null, null);
- }
- }
- this.mOpGroup = new calOperationGroup(cancelFunc);
- }
- return this.mOpGroup;
- },
-
- QueryInterface: function (aIID) {
- if (!aIID.equals(Components.interfaces.nsISupports) &&
- !aIID.equals(Components.interfaces.calIOperationListener))
- {
- throw Components.results.NS_ERROR_NO_INTERFACE;
- }
-
- return this;
- },
-
- onOperationComplete: function (aCalendar, aStatus, aOperationType, aId, aDetail) {
- if (!this.mRealListener) {
- // has been cancelled, ignore any providers firing on this...
- return;
- }
- if (this.mFinished) {
- dump ("+++ calCompositeGetListenerHelper.onOperationComplete: called with mFinished == true!");
- return;
- }
-
- if (!Components.isSuccessCode(aStatus)) {
- // proxy this to a onGetResult
- // XXX - do we want to give the real calendar? or this?
- // XXX - get rid of iid param
- this.mRealListener.onGetResult (aCalendar, aStatus,
- Components.interfaces.nsISupports,
- aDetail, 0, []);
- }
-
- this.mReceivedCompletes++;
-
- if (this.mReceivedCompletes == this.mNumQueries) {
- // we're done here.
- this.mFinished = true;
- this.opGroup.notifyCompleted();
- this.mRealListener.onOperationComplete (this,
- aStatus,
- calIOperationListener.GET,
- null,
- null);
- }
- },
-
- onGetResult: function (aCalendar, aStatus, aItemType, aDetail, aCount, aItems) {
- if (!this.mRealListener) {
- // has been cancelled, ignore any providers firing on this...
- return;
- }
- if (this.mFinished) {
- dump ("+++ calCompositeGetListenerHelper.onGetResult: called with mFinished == true!");
- return;
- }
-
- // ignore if we have a max and we're past it
- if (this.mMaxItems && this.mItemsReceived >= this.mMaxItems)
- return;
-
- if (Components.isSuccessCode(aStatus) &&
- this.mMaxItems &&
- ((this.mItemsReceived + aCount) > this.mMaxItems))
- {
- // this will blow past the limit
- aCount = this.mMaxItems - this.mItemsReceived;
- aItems = aItems.slice(0, aCount);
- }
-
- // send GetResults to the real listener
- this.mRealListener.onGetResult (aCalendar, aStatus, aItemType, aDetail, aCount, aItems);
- this.mItemsReceived += aCount;
- }
-
- };
-
- // nsIFactory
- const calCompositeCalendarFactory = {
- createInstance: function (outer, iid) {
- if (outer != null)
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- return (new calCompositeCalendar()).QueryInterface(iid);
- }
- };
-
- /****
- **** module registration
- ****/
-
- var calCompositeCalendarModule = {
- mCID: Components.ID("{aeff788d-63b0-4996-91fb-40a7654c6224}"),
- mContractID: "@mozilla.org/calendar/calendar;1?type=composite",
-
- mUtilsLoaded: false,
- loadUtils: function compositeLoadUtils() {
- if (this.mUtilsLoaded)
- return;
-
- const jssslContractID = "@mozilla.org/moz/jssubscript-loader;1";
- const jssslIID = Components.interfaces.mozIJSSubScriptLoader;
-
- const iosvcContractID = "@mozilla.org/network/io-service;1";
- const iosvcIID = Components.interfaces.nsIIOService;
-
- var loader = Components.classes[jssslContractID].getService(jssslIID);
- var iosvc = Components.classes[iosvcContractID].getService(iosvcIID);
-
- // Note that unintuitively, __LOCATION__.parent == .
- // We expect to find utils in ./../js
- var appdir = __LOCATION__.parent.parent;
- appdir.append("js");
- var scriptName = "calUtils.js";
-
- var f = appdir.clone();
- f.append(scriptName);
-
- try {
- var fileurl = iosvc.newFileURI(f);
- loader.loadSubScript(fileurl.spec, this.__parent__.__parent__);
- } catch (e) {
- dump("Error while loading " + fileurl.spec + "\n");
- throw e;
- }
-
- this.mUtilsLoaded = true;
- },
-
- registerSelf: function (compMgr, fileSpec, location, type) {
- compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
- compMgr.registerFactoryLocation(this.mCID,
- "Calendar composite provider",
- this.mContractID,
- fileSpec,
- location,
- type);
- },
-
- getClassObject: function (compMgr, cid, iid) {
- if (!cid.equals(this.mCID))
- throw Components.results.NS_ERROR_NO_INTERFACE;
-
- if (!iid.equals(Components.interfaces.nsIFactory))
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-
- this.loadUtils();
-
- return calCompositeCalendarFactory;
- },
-
- canUnload: function(compMgr) {
- return true;
- }
- };
-
- function NSGetModule(compMgr, fileSpec) {
- return calCompositeCalendarModule;
- }
-